package com.dreamchaser.familydevice.shiro.filter;


import com.dreamchaser.familydevice.config.SpringContextHolder;
import com.dreamchaser.familydevice.service.IAccountService;
import com.dreamchaser.familydevice.shiro.RestPathMatchingFilterChainResolver;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author
 * @Description Filter 管理器
 * shiro 主入口
 */
@Component
@Slf4j
public class ShiroFilterChainManager {


    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroFilterChainManager.class);

    private final StringRedisTemplate redisTemplate;
    private final com.dreamchaser.familydevice.service.IAccountService IAccountService;

    @Autowired
    public ShiroFilterChainManager(StringRedisTemplate redisTemplate, IAccountService IAccountService) {
        this.redisTemplate = redisTemplate;
        this.IAccountService = IAccountService;
    }

    // 初始化获取过滤链
    public Map<String, Filter> initGetFilters() {
        Map<String, Filter> filters = new LinkedHashMap<>();
        // 基于密码的过滤器
//        PasswordFilter passwordFilter = new PasswordFilter();
//        passwordFilter.setRedisTemplate(redisTemplate);
//        filters.put("auth", passwordFilter);
        // jwt token 过滤器
        RestJwtFilter jwtFilter = new RestJwtFilter();
        jwtFilter.setRedisTemplate(redisTemplate);
        jwtFilter.setIAccountService(IAccountService);

        filters.put("jwt", jwtFilter);
        return filters;
    }

    public static List<String> getDefaultIgnore() {
        List<String> defalutAnon = new ArrayList<>();
        defalutAnon.add("/**/*.js");
        defalutAnon.add("/**/*.css");
        defalutAnon.add("/logout");
        defalutAnon.add("/**/*.ico");
        defalutAnon.add("/druid/**");
        //放行webSocket
        defalutAnon.add("/websocket/*");
        //放行swagger
        defalutAnon.add("/swagger-ui.html");
        defalutAnon.add("/doc.html");
        defalutAnon.add("/swagger**/**");
        defalutAnon.add("/swagger-resources");
        defalutAnon.add("/v2/api-docs");
        defalutAnon.add("/error");
        defalutAnon.add("/webjars/springfox-swagger-ui/**");
        return defalutAnon;
    }

    // 初始化获取过滤链规则
    public Map<String, String> initGetFilterChain() {
        Map<String, String> filterChain = new LinkedHashMap<>();
        // -------------anon 默认过滤器忽略的URL


        //============api ========
        //defalutAnon.add("/account/waiterLogin");
        /**
         * 加入anon anon为shiro默认过滤标识
         */
        getDefaultIgnore().forEach(ignored -> filterChain.put(ignored, "anon"));

//        urls.forEach(ignored -> filterChain.put(ignored, "anon"));
        // -------------auth 默认需要认证过滤器的URL 走auth--PasswordFilter
//        List<String> defalutAuth = Arrays.asList("/account/**");
//        defalutAuth.forEach(auth -> filterChain.put(auth, "auth"));
        // -------------dynamic 动态URL
        /**
         * 加入jwt认证 anon为shiro默认过滤标识
         */
        filterChain.put("/**", "jwt");
        // jwt[admin] admin 角色



        // 动态根据数据库配置加入anon或者jwt
        //if (shiroFilterRulesProvider != null) {
        //    List<RolePermRuleDto> rolePermRuleDtos = this.shiroFilterRulesProvider.loadRolePermRules();
        //    if (null != rolePermRuleDtos) {
        //        rolePermRuleDtos.forEach(rule -> {
        //            StringBuilder chain = rule.toFilterChain();
        //            if (null != chain) {
        //                filterChain.putIfAbsent(rule.getUrl(), chain.toString());
        //            }
        //        });
        //    }
        //}

        // 无用
        //shiroFilterRulesProvider
//        select concat(a.uri, "==", a.`method`) as url, group_concat(c.code) as needRoles
//        from auth_resource a
//        left join auth_role_resource b on b.`resource_id` = a.`id`
//        left join auth_role c on b.`role_id` = c.`id`
//        where a.`type` = 2
//        and a.`status` = 1
//        group by a.id
//
//        /**
//         * @Description 将url needRoles 转化成shiro可识别的过滤器链：url=jwt[角色1、角色2、角色n]
//         * @Param []
//         * @Return java.lang.StringBuilder
//         */
//        public StringBuilder toFilterChain() {
//
//            if (StringUtils.isEmpty(url))
//                return null;
//            StringBuilder stringBuilder = new StringBuilder();
//            if (StringUtils.isEmpty(this.needRoles)) {
//                needRoles = "role_unauth";
//                //return null;
//            }
//            String[] strings = this.needRoles.split(",");
//            Set<String> setRole = new HashSet<>(CollectionUtils.arrayToList(strings));
//            // 约定若role_anon角色拥有此uri资源的权限,则此uri资源直接访问不需要认证和权限
//            if (setRole.contains("role_anon")) {
//                stringBuilder.append("anon");
//            } else {
//                //  其他自定义资源uri需通过jwt认证和角色认证
//                stringBuilder.append("jwt").append("[").append(this.getNeedRoles()).append("]");
//            }
//            return stringBuilder;
//        }

        return filterChain;
    }

    // 动态重新加载过滤链规则
    public void reloadFilterChain(List<String> urls) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = SpringContextHolder.getBean(ShiroFilterFactoryBean.class);
        AbstractShiroFilter abstractShiroFilter = null;
        try {
            abstractShiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            RestPathMatchingFilterChainResolver filterChainResolver = (RestPathMatchingFilterChainResolver) abstractShiroFilter.getFilterChainResolver();
            DefaultFilterChainManager filterChainManager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();

            filterChainManager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            Map<String, String> map = new LinkedHashMap<>();

            urls.forEach(ignored -> map.put(ignored.replaceAll("\\{[\\w]+?\\}","*"), "anon"));
            map.putAll(this.initGetFilterChain());
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
            shiroFilterFactoryBean.getFilterChainDefinitionMap().forEach((k, v) -> filterChainManager.createChain(k, v));
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
}
